using System;
using System.Collections.Generic;
using System.Text;
using OpenComposite.EII.Designer.SCA;
using System.CodeDom;
using OpenComposite.EII.Repository;
using System.Xml;

namespace OpenComposite.EII.CodeGenerators
{
	public static class ClassGenerator
	{
		//private static RepositoryService repSvc = null;

		public static string GenerateCodeForITComponent(IServiceProvider serviceProvider, ServiceComponentSymbol component)
		{
			if ( component.Interfaces.Count == 0 || component.Interfaces[0].Operations.Count == 0 )
				throw new Exception("No interface/operations defined.");

			// create namespace
			CodeNamespace codens = new CodeNamespace(RepositoryService.GetIdentifier(component.Parent.Text));
			codens.Imports.Add(new CodeNamespaceImport("System"));
			codens.Imports.Add(new CodeNamespaceImport("System.Collections.Generic"));
			codens.Imports.Add(new CodeNamespaceImport("System.Text"));
			codens.Imports.Add(new CodeNamespaceImport("System.Xml"));


			if ( component.Interfaces.Count == 1 ) {
				codens.Types.Add(
					createClass(RepositoryService.GetIdentifier(component.Text), component.Interfaces[0]));
			} else {
				int count = 0;
				string name = RepositoryService.GetIdentifier(component.Text);
				foreach ( InterfaceSymbol isymbol in component.Interfaces ) {
					string classname = "";
					if ( isymbol.Text != "Service" )
						classname = RepositoryService.GetIdentifier(isymbol.Text);
					else {
						classname = name + count.ToString();
						count++;
					}
					codens.Types.Add(createClass(classname, isymbol));
				}
			}
			return CSharpGenerator.GenerateCodeString(codens);
		}

		private static CodeTypeDeclaration createClass(string classname, InterfaceSymbol interfaceSymbol)
		{
			// create class
			CodeTypeDeclaration codeclass = new CodeTypeDeclaration(classname);
			codeclass.IsClass = true;
			
			// add empty constuctor
			CodeConstructor constructor = new CodeConstructor();
			constructor.Attributes = MemberAttributes.Public | MemberAttributes.Final;
			constructor.Statements.Add(new CodeCommentStatement("TODO: add constructor code"));
			codeclass.Members.Add(constructor);

			// add interface operation as methods
			foreach ( Operation op in interfaceSymbol.Operations ) {
				codeclass.Members.Add(createMethod(op));
			}
			return codeclass;
		}

		private static CodeMemberMethod createMethod(Operation op)
		{
			// create method
			CodeMemberMethod method = new CodeMemberMethod();
			method.Name = RepositoryService.GetIdentifier(op.Name);
			method.Attributes = MemberAttributes.Public | MemberAttributes.Final;

			// add output type
			method.ReturnType = new CodeTypeReference(typeof(XmlNode));

			// add input parameter
			method.Parameters.Add(new CodeParameterDeclarationExpression(typeof(XmlNode), "xnInput"));

			// add todo comment
			method.Statements.Add(new CodeCommentStatement("TODO: add method code"));

			return method;
		}
	}
}
